/****************************************************************************
** Copyright (C) 2017 ZhouLiQiu(zhouliqiu@126.com).
**
** This file is part of the qtc_cppcheck, It is a plugin for Qt Creator.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
**
****************************************************************************/
#include "cdlgcheckproject.h"
#include "ui_cdlgcheckproject.h"

#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>

#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/target.h>

#include <qmakeprojectmanager/qmakenodes.h>
#include <qmakeprojectmanager/qmakeproject.h>

#include <QMessageBox>
#include <QFileInfo>
#include <QDebug>

#include "worker_check.h"

namespace qtc_cppcheck {
namespace Internal {

CDlgCheckProject::CDlgCheckProject(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CDlgCheckProject)
{
    ui->setupUi(this);

    ui->treeWidget->setColumnWidth(0, 220);

    connect(ui->treeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this,
            SLOT(setCollapsedIcon(QTreeWidgetItem *)));
    connect(ui->treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem *)), this,
            SLOT(setExpandedIcon(QTreeWidgetItem *)));

    m_headerItem = new QTreeWidgetItem(ui->treeWidget);
    m_headerItem->setText(0, QString("头文件"));
    m_headerItem->setIcon(0, QIcon(QLatin1String(":/res/close.png")));
    m_headerItem->setFlags(m_headerItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
    m_headerItem->setCheckState(0, Qt::Unchecked);

    m_sourceItem = new QTreeWidgetItem(ui->treeWidget);
    m_sourceItem->setText(0, QString("源文件"));
    m_sourceItem->setIcon(0, QIcon(QLatin1String(":/res/close.png")));
    m_sourceItem->setFlags(m_sourceItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
    m_sourceItem->setCheckState(0, Qt::Unchecked);

    connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(refreshFile()));

    m_worker_check = new Worker_Check(this);
    connect(m_worker_check, SIGNAL(sig_check_progress(int)), this, SLOT(slot_check_progress(int)));
    connect(m_worker_check, SIGNAL(sig_finished(int, QProcess::ExitStatus, int, int, int, int, int)), this,
            SLOT(slot_check_finished(int, QProcess::ExitStatus, int, int, int, int, int)));

    initProject();

    resize(600, 500);
}

CDlgCheckProject::~CDlgCheckProject()
{
    m_worker_check->stopCheck();
    delete m_worker_check;
    delete ui;
}

void CDlgCheckProject::closeEvent(QCloseEvent *e)
{
    if (m_worker_check->isRunning())
    {
        e->ignore();
        return;
    }
    e->accept();
}

void CDlgCheckProject::initProject()
{
    Core::EditorManager *em = Core::EditorManager::instance();
    if (!em)
    {
        return;
    }

    QmakeProjectManager::QmakeProject *project =
        static_cast<QmakeProjectManager::QmakeProject *>(ProjectExplorer::ProjectTree::currentProject());
    if (!project)
    {
        return;
    }
    auto t = project->activeTarget();
    auto bs = dynamic_cast<QmakeProjectManager::QmakeBuildSystem *>(t ? t->buildSystem() : nullptr);
    if (!bs)
    {
        return;
    }

    QList<QmakeProjectManager::QmakeProFile *> pro = bs->rootProFile()->allProFiles();
    for (int i = 0; i < pro.size(); ++i)
    {
        const QmakeProjectManager::QmakeProFile *node = pro.at(i);
        ui->comboBox->addItem(node->displayName());
    }

    if (ui->comboBox->count() > 1)
    {
        ui->comboBox->setCurrentIndex(0);
        ui->comboBox->setEnabled(true);
    }
}

void CDlgCheckProject::on_btnCheck_clicked()
{
    if (!m_worker_check->isRunning())
    {
        QStringList fileList;
        int i;
        QTreeWidgetItem *item = NULL;
        for (i = 0; i < m_headerItem->childCount(); ++i)
        {
            item = m_headerItem->child(i);
            if (item->checkState(0) != Qt::Unchecked)
            {
                fileList << item->data(0, Qt::UserRole).toString();
            }
        }
        for (i = 0; i < m_sourceItem->childCount(); ++i)
        {
            item = m_sourceItem->child(i);
            if (item->checkState(0) != Qt::Unchecked)
            {
                fileList << item->data(0, Qt::UserRole).toString();
            }
        }
        if (fileList.size() > 0)
        {
            ui->progressBar->setMinimum(0);
            ui->progressBar->setMaximum(100);
            ui->progressBar->setValue(0);
            //停止
            ui->btnCheck->setText(QString("停止检测"));
            ui->btnClose->setEnabled(false);

            m_worker_check->checkFiles(fileList);
        }
    }
    else
    {
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
        m_worker_check->stopCheck();
        ui->progressBar->setValue(0);
        ui->btnCheck->setText(QString("开始检测"));
        ui->btnClose->setEnabled(true);

        QApplication::restoreOverrideCursor();
    }
}

void CDlgCheckProject::on_btnClose_clicked()
{
    reject();
}

void CDlgCheckProject::setCollapsedIcon(QTreeWidgetItem *item)
{
    item->setIcon(0, QIcon(QLatin1String(":/res/close.png")));
}

void CDlgCheckProject::setExpandedIcon(QTreeWidgetItem *item)
{
    item->setIcon(0, QIcon(QLatin1String(":/res/open.png")));
}

void CDlgCheckProject::refreshFile()
{
    ui->treeWidget->setEnabled(false);
    ui->btnCheck->setEnabled(false);
    m_headerItem->setCheckState(0, Qt::Unchecked);
    m_sourceItem->setCheckState(0, Qt::Unchecked);
    ui->progressBar->setValue(0);

    while (m_headerItem->childCount() > 0)
    {
        delete m_headerItem->takeChild(0);
    }
    while (m_sourceItem->childCount() > 0)
    {
        delete m_sourceItem->takeChild(0);
    }
    if (ui->comboBox->currentIndex() < 0)
    {
        return;
    }
    int proIdx = ui->comboBox->currentIndex();

    QmakeProjectManager::QmakeProject *project =
        static_cast<QmakeProjectManager::QmakeProject *>(ProjectExplorer::ProjectTree::currentProject());
    if (!project)
    {
        return;
    }
    auto t = project->activeTarget();
    auto bs = dynamic_cast<QmakeProjectManager::QmakeBuildSystem *>(t ? t->buildSystem() : nullptr);
    if (!bs)
    {
        return;
    }

    QList<QmakeProjectManager::QmakeProFile *> pro = bs->rootProFile()->allProFiles();
    const QmakeProjectManager::QmakeProFile *node = pro.at(proIdx);
    //list all source files
    QStringList files;
    files << node->variableValue(QmakeProjectManager::Variable::ExactSource);
    for (int i = 0; i < files.size(); ++i)
    {
        QFileInfo fi = QFileInfo(files.at(i));
        int fileType = getFileType(files.at(i));
        if (fileType == 0)
        {
            QTreeWidgetItem *item = new QTreeWidgetItem(m_headerItem);
            item->setFlags(item->flags() & ~Qt::ItemIsAutoTristate);
            item->setText(0, fi.fileName());
            item->setData(0, Qt::UserRole, files.at(i));
            item->setText(1, QDir::toNativeSeparators(fi.path()));
            item->setCheckState(0, Qt::Unchecked);
            item->setIcon(0, QIcon(QLatin1String(":/res/h32.png")));
        }
        else if (fileType == 1)
        {
            QTreeWidgetItem *item = new QTreeWidgetItem(m_sourceItem);
            item->setFlags(item->flags() & ~Qt::ItemIsAutoTristate);
            item->setText(0, fi.fileName());
            item->setData(0, Qt::UserRole, files.at(i));
            item->setText(1, QDir::toNativeSeparators(fi.path()));
            item->setCheckState(0, Qt::Unchecked);
            item->setIcon(0, QIcon(QLatin1String(":/res/cpp32.png")));
        }
    }
    if (m_headerItem->childCount() > 0)
    {
        m_headerItem->setCheckState(0, Qt::Checked);
        ui->treeWidget->setEnabled(true);
    }
    if (m_sourceItem->childCount() > 0)
    {
        m_sourceItem->setCheckState(0, Qt::Checked);
        ui->treeWidget->setEnabled(true);
    }
    m_headerItem->setExpanded(true);
    m_sourceItem->setExpanded(true);
    on_treeWidget_itemClicked(NULL, 0);
}

int CDlgCheckProject::getFileType(QString fileName)
{
    QFileInfo fi = QFileInfo(fileName);
    if (fi.exists() == false)
    {
        return -1;
    }
    fileName = fileName.toLower();
    if (fileName.endsWith(".h") ||
            fileName.endsWith(".hpp") ||
            fileName.endsWith(".hxx"))
    {
        return 0;
    }
    else if (fileName.endsWith(".c") ||
             fileName.endsWith(".cpp") ||
             fileName.endsWith(".cc") ||
             fileName.endsWith(".cxx") ||
             fileName.endsWith(".c++"))
    {
        return 1;
    }
    else
    {
        return 2;
    }
}

void CDlgCheckProject::slot_check_progress(int value)
{
    ui->progressBar->setValue(value);
}

void CDlgCheckProject::slot_check_finished(int exitCode, QProcess::ExitStatus exitStatus,
        int error, int warn, int style, int portability, int performance)
{
    ui->btnCheck->setText(QString("开始检测"));
    ui->btnClose->setEnabled(true);
    QString strInfo;
    if (exitCode == 62097)  // kill process
    {
        strInfo = QString("停止CppCheck检测成功");
    }
    else if (exitCode == -1 || exitStatus == QProcess::CrashExit)
    {
        strInfo = QString("启动CppCheck检测失败，请在选项中检查cppcheck程序配置是否正确");
    }
    else
    {
        strInfo = QString("检测结果：        \n错误等级：  %1\n警告等级：  %2\n性能等级：  %3\n可移植性：  %4\n风格等级：  %5\n")
                  .arg(error)
                  .arg(warn)
                  .arg(performance)
                  .arg(portability)
                  .arg(style);
    }
    QMessageBox::information(this, QString("完成"), strInfo);
}

void CDlgCheckProject::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
{
    Q_UNUSED(item);
    Q_UNUSED(column);
    Qt::CheckState ret1 = m_headerItem->checkState(0);
    Qt::CheckState ret2 = m_sourceItem->checkState(0);
    if (ret1 == Qt::Unchecked && ret2 == Qt::Unchecked)
    {
        ui->btnCheck->setEnabled(false);
    }
    else
    {
        ui->btnCheck->setEnabled(true);
    }
}

} // namespace Internal
} // namespace qtc_cppcheck


